﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows.Forms;

using HelperLibrary;
using MasterLibrary.Windows.Forms;

namespace Prometheus
{
    static class Program
    {
        private static MainForm mainForm;
        private static NotifyIcon notifyIcon;
        private static ContextMenuStrip menuStrip;
        private static System.Windows.Forms.Timer backupTimer;
        private static int waitTime = 0;
        private static Mutex mutex;

        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        static void Main()
        {
            if (IsOtherInstanceRunning())
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new SecondInstanceForm());
            }
            else
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);

                var frmSplash = SplashHelper.RunSplash<SplashForm>();
                var splashMessage = SplashHelper.GetAsyncMessenger<string>(frmSplash.Message);

                splashMessage("Initializing application ...");
                Thread.Sleep(1000);

                AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
                Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
                Application.ApplicationExit += new EventHandler(Application_ApplicationExit);

                splashMessage("Registering globals ...");
                Thread.Sleep(200);

                // initialize timer
                backupTimer = new System.Windows.Forms.Timer();
                backupTimer.Tick += new EventHandler(backupTimer_Tick);
                backupTimer.Interval = 5000;

                // initialize notify icon
                notifyIcon = new NotifyIcon();
                notifyIcon.Icon = global::Prometheus.Properties.Resources.Download;
                notifyIcon.Text = "Prometheus";
                notifyIcon.DoubleClick += new EventHandler(notifyIcon_DoubleClick);
                notifyIcon.ContextMenuStrip = new ContextMenuStrip();

                // initialize menu strip
                menuStrip = notifyIcon.ContextMenuStrip;

                splashMessage("Register timer ...");
                Thread.Sleep(200);

                splashMessage("Building environment ...");
                Thread.Sleep(200);

                // switch systray state
                if (Globals.appConfig.StartSysTray)
                {
                    notifyIcon.Visible = true;
                    backupTimer.Start();
                }
                else
                {
                    InitializeMainForm();
                }

                frmSplash.BeginInvoke(new Action(frmSplash.Close));
                Application.Run();
            }
        }

        public static bool IsOtherInstanceRunning()
        {
            string mutexName = Application.ProductName + "_MultiStartPrevent";
            mutex = new Mutex(false, mutexName);

            if (mutex.WaitOne(0, true))
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        #region MainForm Methods
        private static void InitializeMainForm()
        {
            if (mainForm == null)
            {
                mainForm = new MainForm();
                mainForm.Minimized += new EventHandler(mainForm_Minimized);
                mainForm.BackupCompleted += new EventHandler(mainForm_BackupCompleted);
                notifyIcon.Visible = false;
                backupTimer.Stop();
                mainForm.Show();
            }
            else
            {
                mainForm.Hide();
                mainForm.Dispose();
                mainForm = null;

                notifyIcon.Visible = true;
                backupTimer.Start();
            }
        }

        private static void mainForm_BackupCompleted(object sender, EventArgs e)
        {
            BackupProcessStarted = false;
            Globals.appConfig.LastBackup = DateTime.Now.ToShortDateString() + " / " + DateTime.Now.ToShortTimeString();

            if (Globals.appConfig.StartTime < DateTime.Now)
                UpdateBackupInterval();
        }
        #endregion

        #region Global Exception Handler
        // global exception handler
        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            try
            {
                Globals.ShowExceptionForm((Exception)e.ExceptionObject, mainForm);
            }
            catch 
            {
                Application.Exit();
            }
        }
        static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            try
            {
                Globals.ShowExceptionForm(e.Exception, mainForm);
            }
            catch
            {
                Application.Exit();
            }
        }
        #endregion

        #region Application Exit / Minimize / Maximize

        // application exit event
        static void Application_ApplicationExit(object sender, EventArgs e)
        {
            notifyIcon.Visible = false;
            notifyIcon.Dispose();
            notifyIcon = null;

            menuStrip.Dispose();
            menuStrip = null;

            mainForm.Dispose();
            mainForm = null;

            GC.Collect();
        }

        // show notify icon on form minimizing
        static void mainForm_Minimized(object sender, EventArgs e)
        {
            InitializeMainForm();
        }

        // show form on notify icon double click
        static void notifyIcon_DoubleClick(object sender, EventArgs e)
        {
            InitializeMainForm();
        }

        #endregion

        private static void UpdateBackupInterval()
        {
            switch (Globals.appConfig.TypeInterval)
            {
                case Timetype.Days:
                    Globals.appConfig.StartTime = DateTime.Now.AddDays(Globals.appConfig.ValueInterval);
                    break;
                case Timetype.Hours:
                    Globals.appConfig.StartTime = DateTime.Now.AddHours(Globals.appConfig.ValueInterval);
                    break;
                case Timetype.Minutes:
                    Globals.appConfig.StartTime = DateTime.Now.AddMinutes(Globals.appConfig.ValueInterval);
                    break;
                case Timetype.Months:
                    Globals.appConfig.StartTime = DateTime.Now.AddDays(Globals.appConfig.ValueInterval * 7 * 30);
                    break;
                case Timetype.Weeks:
                    Globals.appConfig.StartTime = DateTime.Now.AddDays(Globals.appConfig.ValueInterval * 7);
                    break;
            }

            Globals.SaveConfiguration(Globals.appConfig);
        }

        private static bool BackupProcessStarted = false;
        private static void backupTimer_Tick(object sender, EventArgs e)
        {
            // use wait timer
            if (Globals.appConfig.UseWait)
            {
                int targetTime = 0;

                switch (Globals.appConfig.TypeWait)
                {
                    case Timetype.Minutes:
                        {
                            targetTime = 60 * Globals.appConfig.ValueWait;
                            break;
                        }
                    case Timetype.Hours:
                        {
                            targetTime = 60 * 60 * Globals.appConfig.ValueWait;
                            break;
                        }
                    case Timetype.Days:
                        {
                            targetTime = 60 * 60 * 24 * Globals.appConfig.ValueWait;
                            break;
                        }
                    case Timetype.Weeks:
                        {
                            targetTime = 60 * 60 * 24 * 7 * Globals.appConfig.ValueWait;
                            break;
                        }
                    case Timetype.Months:
                        {
                            targetTime = 60 * 60 * 24 * 7 * 30 * Globals.appConfig.ValueWait;
                            break;
                        }
                }

                waitTime += 5;
                if (waitTime < targetTime)
                    return;
            }

            if (Globals.appConfig.UseInterval)
            {
                // backup timer
                if (Globals.appConfig.StartTime <= DateTime.Now)
                {
                    // allow only one backup process
                    if (!BackupProcessStarted)
                    {
                        BackupProcessStarted = true;

                        // should the application use the request form
                        if (Globals.appConfig.UseRequest)
                        {
                            RequestForm reqForm = new RequestForm();
                            DialogResult result = reqForm.ShowDialog(mainForm);

                            if (result == DialogResult.OK)
                            {
                                InitializeMainForm();
                                mainForm.LoadPage("DoBackup");
                            }
                            else
                            {
                                UpdateBackupInterval();
                                BackupProcessStarted = false;
                            }
                        }
                        else
                        {
                            InitializeMainForm();
                            mainForm.LoadPage("DoBackup");
                        }
                    }
                }
            }
        }
    }
}
